#include "opencvrenderer.h"
#include "inputimage.h"
#include "stitcher.h"
#include "commandlineoptions.h"
#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <opencv/cv.h>
#include "imageset.h"

using namespace std;
using namespace cshotel;
using namespace boost;
using namespace boost::filesystem;
using namespace cv;

OpenCVRenderer::OpenCVRenderer(shared_ptr<ImageSet> imgs) : imageSet(imgs) {}

void OpenCVRenderer::render() {
    dout("Rendering output ..." << endl);
    
    ImageSet::BoundingBox boundingBox = imageSet->getBoundingBox();
    dout("    total bounding box: corner (" << boundingBox.minX << ", " << boundingBox.minY << "), size (" << boundingBox.width << ", " << boundingBox.height << ")" << endl);
    
    bool generatePanorama = CommandLineOptions::getInstance().getOutputFormat() != CommandLineOptions::TransformedFiles;
    
    Mat panorama;
    
    foreach(shared_ptr<InputImage> img, imageSet->getImages()) {
        dout("    transforming image " << img->getId() << endl);
        
        shared_ptr<Mat> imageFile = img->getImage();
        
        if(!generatePanorama) {
            string originalFileName = img->getName();
            string transformedFileName = getTransformedVersionFileName(path(originalFileName).filename());
            
            // get the size and position of the current image
            double offsetX = floor(img->getTransformedVersionOffset().x);
            double offsetY = floor(img->getTransformedVersionOffset().y);
            int sizeX = ceil(img->getTransformedVersionImageSize().width);
            int sizeY = ceil(img->getTransformedVersionImageSize().height);
            dout("        offset: (" << offsetX << ", " << offsetY << ")  size: (" << sizeX << ", " << sizeY << ")" << endl);
            dout("        rendering ..." << endl);
            
            Mat translation = (Mat_<double>(3, 3) << 1, 0, -offsetX, 0, 1, -offsetY, 0, 0, 1);
            Mat dest;
            warpPerspective(*imageFile, dest, translation * img->getGlobalHomography(), Size(sizeX, sizeY), INTER_LANCZOS4, BORDER_TRANSPARENT);
            
            dout("        writing to " << transformedFileName << " ..." << endl);
            imwrite(transformedFileName.c_str(), dest);
            img->setTransformedVersion(transformedFileName);
        } else {
            int sizeX = ceil(boundingBox.width);
            int sizeY = ceil(boundingBox.height);
            
            dout("        offset: (" << -boundingBox.minX << ", " << -boundingBox.minY << ")  size: (" << sizeX << ", " << sizeY << ")" << endl);
            dout("        rendering ..." << endl);
            
            Mat translation = (Mat_<double>(3, 3) << 1, 0, -boundingBox.minX, 0, 1, -boundingBox.minY, 0, 0, 1);
            warpPerspective(*imageFile, panorama, translation * img->getGlobalHomography(), Size(sizeX, sizeY), INTER_LANCZOS4, BORDER_TRANSPARENT);
        }
    }
    
    if(generatePanorama) {
        string panoramaFileName = getPanoramaFileName();
        dout("    writing panorama file to " << panoramaFileName << " ..." << endl);
        imwrite(panoramaFileName.c_str(), panorama);
        
        if(CommandLineOptions::getInstance().getOutputFormat() == CommandLineOptions::SeaDragon) {
            string deepzoomcommand = buildDeepZoomConverterCommand();
            dout("    running DeepZoom converter: " << deepzoomcommand << endl);
            std::system(deepzoomcommand.c_str());
        }
        
        if(CommandLineOptions::getInstance().getCreateThumbnail()) {
            dout("    creating thumbnail " << getThumbnailFileName() << "..." << endl);
            createThumbnail();
        }
    }
}
